#ifndef L4_PACKET_H
#define L4_PACKET_H

#include <stdint.h>
#include "pkt_meta_def.h"
#include "tcp_packet.h"

namespace secsmart_tcpip
{

enum l4_pkt_error_code
{
    L4_PKT_OK = 0,
    L4_PKT_ERR, // 丢包
    L4_PKT_FILTER, // 报文被过滤
    L4_PKT_DROP_MAX,
    L4_PKT_CACHED  // 缓存报文
};

typedef struct l4_pkt_stat {
    uint64_t rcv_pkt_num;
    uint64_t rcv_pkt_bytes;
    uint64_t snd_pkt_num;
    uint64_t snd_pkt_bytes;
    uint64_t drop_pkt_num[L4_PKT_DROP_MAX];
    uint64_t cached_pkt_num;

    void stat_rcv_pkt(uint32_t pkt_len)
    {
        rcv_pkt_num++;
        rcv_pkt_bytes += pkt_len;
    }

    void stat_snd_pkt(uint32_t pkt_len)
    {
        snd_pkt_num++;
        snd_pkt_bytes += pkt_len;
    }

    void stat_cache_pkt()
    {
        cached_pkt_num++;
    }

    void stat_drop_pkt(uint32_t type)
    {
        if (type >= L4_PKT_DROP_MAX) {
            return;
        }
        drop_pkt_num[type]++;
    }

    void stat_clear()
    {
        rcv_pkt_num = 0;
        rcv_pkt_bytes = 0;
        snd_pkt_num = 0;
        snd_pkt_bytes = 0;
        cached_pkt_num = 0;
        for (int i = 0; i < L4_PKT_DROP_MAX; i++) {
            drop_pkt_num[i] = 0;
        }
    }
}l4_pkt_stat_t;


class L4PacketHandler
{
public:
    L4PacketHandler() { init(); }
    ~L4PacketHandler() { uninit(); }
    void init();
    void uninit();

    // 注册上层业务的回调接口，在tcp链接建立、收到数据、结束连接时，会调用注册的TcpEventProc cb接口。
    void register_tcp_conn_event_cb(tcp_conn_event_cb_t cb, void *user_data);

    /*
     * @brief 对4层报文（TCP/UDP)报文进行处理
     * @param in_pkt: 报文内容，包含TCP/UDP头部和载荷内容，不含IP头部信息
     * @param meta 原始报文的基本信息
     * @return 
     */
    uint32_t process_packet(uint8_t *in_pkt, packet_meta_t *meta);

    // 修改配置参数
    void set_tcp_reassemble_enable(bool enable)
    {
        if (m_tcp_handler == nullptr) {
            return;
        }
        m_tcp_handler->set_cfg_reassemble_enable(enable);
    }

    void set_tcp_cfg(tcp_cfg_t &cfg)
    {
        if (m_tcp_handler != nullptr) {
            m_tcp_handler->set_cfg(cfg);
        }
    }

    void get_tcp_cfg(tcp_cfg_t &cfg)
    {
        if (m_tcp_handler == nullptr) {
            return;
        }
        cfg =  *m_tcp_handler->get_cfg();
    }

    tcp_statistic_t get_tcp_stat()
    {
        tcp_statistic_t stat;
        stat.clear();
        if (m_tcp_handler != nullptr) {
           stat = *m_tcp_handler->get_statistic();
        }
        return stat;
    }

    TcpPacketHandler *get_tcp_handler() { return m_tcp_handler;}

    void set_filter_packet(bool enable) {m_enable_filter_packet = enable;}

    l4_pkt_stat_t get_pkt_stat() { return m_stat; }
    
private:
    bool m_enable_filter_packet;
    TcpPacketHandler *m_tcp_handler; // TCP重组处理器
    l4_pkt_stat_t m_stat;

    bool filter_packet(packet_meta_t *meta);
    uint32_t process_tcp_packet(uint8_t *pkt, packet_meta_t *meta);
    uint32_t process_udp_packet(uint8_t *pkt, packet_meta_t *meta);
};

}


#endif
